namespace Jsl.FxCop
{
    using System;
    using Microsoft.FxCop.Sdk;

    /// <summary>
    /// Warns about calling ToString on a String.
    /// </summary>
    /// <remarks>
    /// Obviously, the call to ToString is redundant...
    /// </remarks>
    public class DoNotUseToStringOnAString : BaseIntrospectionRule
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="DoNotUseToStringOnAString"/> class.
        /// </summary>
        public DoNotUseToStringOnAString()
            : base(typeof(DoNotUseToStringOnAString).Name, "Jsl.FxCop.Rules", typeof(DoNotUseToStringOnAString).Assembly)
        {
        }
        #endregion Constructors

        #region Public Methods
        /// <summary>
        /// Checks the specified member.
        /// </summary>
        /// <param name="member">The member.</param>
        /// <returns>The problems found if any.</returns>
        public override ProblemCollection Check(Member member)
        {
            this.Visit(member);

            return this.Problems;
        }

        /// <summary>
        /// Visits the method call.
        /// </summary>
        /// <param name="call">The call being visited.</param>
        public override void VisitMethodCall(MethodCall call)
        {
            if (call == null)
            {
                throw new ArgumentNullException("call");
            }

            if (call.Operands.Count == 0)
            {
                var memberBinding = call.Callee as MemberBinding;
                if (memberBinding != null)
                {
                    // The method being called is Object.ToString and the target object is a string.
                    if ((memberBinding.BoundMember.FullName == WellKnownTypeNames.Object + "." + WellKnownMethodNames.ToString)
                        && (memberBinding.TargetObject.Type.FullName == WellKnownTypeNames.String))
                    {
                        this.Problems.Add(new Problem(this.GetResolution(), call.SourceContext));
                    }
                }
            }

            base.VisitMethodCall(call);
        }
        #endregion Public Methods
    }
}